package com.mapforge.gui.frames.tileset;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.mapforge.ActionCommands;
import com.mapforge.listener.TileMapCreationEvent;
import com.mapforge.listener.TileMapCreationListener;
import com.mapforge.listener.TilesetEditListener;
import com.mapforge.map.Tileset;

/**
 * 
 * @author Will Morrison
 * 
 */
public class TilesetEditorDialog extends JDialog implements ActionListener,
		TileMapCreationListener {
	/**
	 * Default serial version ID, here to remove warnings
	 */
	private static final long serialVersionUID = 1L;
	public static final String TITLE = "Tileset Editor";
	
	private ChangeListener tilesetChangeListener;
	List<TilesetEditListener> tilesetEditListeners;

	/**
	 * Tileset this dialog is allowing edits to be performed on.
	 */
	private Tileset tileset;
	
	private JTabbedPane tilesetEditorTabs;
	private TilesetPropertiesPanel tilesetPropertiesPanel;
	private JPanel buttonPanel;
	private JButton applyBtn;
	private JButton saveBtn;
	private JButton cancelBtn;

	private static final FlowLayout LEFT_FLOW = new FlowLayout(FlowLayout.LEFT,
			2, 2);

	/**
	 * 
	 * @param frame
	 * @param listeners
	 */
	protected TilesetEditorDialog(JFrame frame, List<TilesetEditListener> listeners) {
		super(frame, TITLE, true);
		tilesetEditListeners = listeners;
		tilesetChangeListener = new TilesetEditorChangeListener();
		tilesetEditorTabs = new JTabbedPane(JTabbedPane.SCROLL_TAB_LAYOUT) {
			private static final long serialVersionUID = 1L;

			public void addTab(String title, Component c) {
				super.addTab(title, c);
				if (c instanceof TilesetPropertiesPanel) {
					((TilesetPropertiesPanel) c)
							.registerTilesetChangeListener(tilesetChangeListener);
				}
			}
		};
		applyBtn = new JButton("Apply");
		saveBtn = new JButton("Save");
		cancelBtn = new JButton("Cancel");
		cancelBtn.addActionListener(this);
		applyBtn.addActionListener(this);
		saveBtn.addActionListener(this);
		tilesetEditorTabs.addTab("Properties", tilesetPropertiesPanel);

		buttonPanel = new JPanel(LEFT_FLOW);
		buttonPanel.add(applyBtn);
		buttonPanel.add(saveBtn);
		buttonPanel.add(cancelBtn);
		add(tilesetEditorTabs, BorderLayout.CENTER);
		add(buttonPanel, BorderLayout.SOUTH);
	}

	/**
	 * 
	 * @return
	 */
	public JTabbedPane getTabs() {
		return tilesetEditorTabs;
	}

	/**
	 * 
	 * @return
	 */
	public Tileset getTileset() {
		return tileset;
	}

	/**
	 * 
	 * @param tileset
	 */
	public void setTileset(Tileset tileset) {
		this.tileset = tileset;
	}
	
	private void informPanelsOfTileset(){
		// inform all the tileset editor panels that the tileset has changed
		int count = tilesetEditorTabs.getTabCount();
		Component comp;
		TilesetPropertiesPanel tilesetComp;
		for (int i = 0; i < count; i++) {
			comp = tilesetEditorTabs.getComponentAt(i);
			if (comp instanceof TilesetPropertiesPanel) {
				tilesetComp = (TilesetPropertiesPanel) comp;
				tilesetComp.setTileset(tileset);
			}
		}
		setTitle(TITLE + " - " + tileset.getName());
	}

	public TilesetPropertiesPanel getTilesetPropertiesPanel() {
		return tilesetPropertiesPanel;
	}

	public void editCurrentTileset() {
		if(tileset!=null)
			informPanelsOfTileset();
		this.saveBtn.setVisible(false);
		this.applyBtn.setVisible(true);
		setVisible(true);
	}

	public Tileset createNewTileset() {
		// store current tileset, inform all panels of the change
		Tileset currentTileset = tileset;
		tileset = new Tileset("Untitled", 1, 1);
		informPanelsOfTileset();

		this.saveBtn.setVisible(true);
		this.applyBtn.setVisible(false);
		setVisible(true);
		// restore the previous tileset, inform panels of the change
		Tileset newTileset = tileset;
		tileset = currentTileset;
		if (tileset != null)
			informPanelsOfTileset();
		// return new tileset
		return newTileset;
	}

	protected void applyChanges() {
		int count = tilesetEditorTabs.getTabCount();
		Component comp;
		TilesetPropertiesPanel tilesetComp;
		StringBuilder strBuilder = new StringBuilder();
		// let all panels perform thier edits
		for (int i = 0; i < count; i++) {
			comp = tilesetEditorTabs.getComponentAt(i);
			if (comp instanceof TilesetPropertiesPanel) {
				tilesetComp = (TilesetPropertiesPanel) comp;
				try {
					tilesetComp.applyTilesetChanges();
				} catch (Exception e) {
					strBuilder.append(e.toString() + "\n");
				}
			}
		}
		//inform all panels of the new state of the tileset
		this.informPanelsOfTileset();
		if (strBuilder.length() > 0) {
			JOptionPane.showMessageDialog(this,
					"Unable to apply all changes\nDetails:\n"
							+ strBuilder.toString());
		}
	}

	/**
	 * 
	 */
	public void setVisible(boolean value) {
		this.applyBtn.setEnabled(false);
		pack();
		setLocationRelativeTo(getParent());
		super.setVisible(value);
	}

	/**
	 * 
	 */
	public void actionPerformed(ActionEvent e) {
		String s = e.getActionCommand();
		if (s.equals(ActionCommands.NEW_TILESET_CMD)) {
			createNewTileset();
		} else if (s.equals(ActionCommands.EDIT_CURRENT_TILESET_CMD)) {
			this.editCurrentTileset();
		} else if (e.getSource() == applyBtn) {
			applyChanges();
		} else if (e.getSource() == saveBtn) {
			// TODO save tileset
			setVisible(false);
		} else if (e.getSource() == cancelBtn) {
			setVisible(false);
		}
	}

	/**
	 * 
	 */
	public void tileMapCreationPerformed(TileMapCreationEvent mapCreationEvent) {
		tileset = mapCreationEvent.getTileMapCreated().getTileset();
	}

	private class TilesetEditorChangeListener implements ChangeListener {
		public void stateChanged(ChangeEvent e) {
			applyBtn.setEnabled(true);
		}
	}
}
